home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / share / gtk-2.0 / demo / drawingarea.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-04-25  |  8.5 KB  |  323 lines

  1. /* Drawing Area
  2.  *
  3.  * GtkDrawingArea is a blank area where you can draw custom displays
  4.  * of various kinds.
  5.  *
  6.  * This demo has two drawing areas. The checkerboard area shows
  7.  * how you can just draw something; all you have to do is write
  8.  * a signal handler for expose_event, as shown here.
  9.  *
  10.  * The "scribble" area is a bit more advanced, and shows how to handle
  11.  * events such as button presses and mouse motion. Click the mouse
  12.  * and drag in the scribble area to draw squiggles. Resize the window
  13.  * to clear the area.
  14.  */
  15.  
  16. #include <gtk/gtk.h>
  17.  
  18. static GtkWidget *window = NULL;
  19. /* Pixmap for scribble area, to store current scribbles */
  20. static GdkPixmap *pixmap = NULL;
  21.  
  22. /* Create a new pixmap of the appropriate size to store our scribbles */
  23. static gboolean
  24. scribble_configure_event (GtkWidget        *widget,
  25.               GdkEventConfigure *event,
  26.               gpointer         data)
  27. {
  28.   if (pixmap)
  29.     g_object_unref (pixmap);
  30.  
  31.   pixmap = gdk_pixmap_new (widget->window,
  32.                widget->allocation.width,
  33.                widget->allocation.height,
  34.                -1);
  35.  
  36.   /* Initialize the pixmap to white */
  37.   gdk_draw_rectangle (pixmap,
  38.               widget->style->white_gc,
  39.               TRUE,
  40.               0, 0,
  41.               widget->allocation.width,
  42.               widget->allocation.height);
  43.  
  44.   /* We've handled the configure event, no need for further processing. */
  45.   return TRUE;
  46. }
  47.  
  48. /* Redraw the screen from the pixmap */
  49. static gboolean
  50. scribble_expose_event (GtkWidget      *widget,
  51.                GdkEventExpose *event,
  52.                gpointer           data)
  53. {
  54.   /* We use the "foreground GC" for the widget since it already exists,
  55.    * but honestly any GC would work. The only thing to worry about
  56.    * is whether the GC has an inappropriate clip region set.
  57.    */
  58.   
  59.   gdk_draw_drawable (widget->window,
  60.              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
  61.              pixmap,
  62.              /* Only copy the area that was exposed. */
  63.              event->area.x, event->area.y,
  64.              event->area.x, event->area.y,
  65.              event->area.width, event->area.height);
  66.   
  67.   return FALSE;
  68. }
  69.  
  70. /* Draw a rectangle on the screen */
  71. static void
  72. draw_brush (GtkWidget *widget,
  73.         gdouble    x,
  74.         gdouble    y)
  75. {
  76.   GdkRectangle update_rect;
  77.  
  78.   update_rect.x = x - 3;
  79.   update_rect.y = y - 3;
  80.   update_rect.width = 6;
  81.   update_rect.height = 6;
  82.  
  83.   /* Paint to the pixmap, where we store our state */
  84.   gdk_draw_rectangle (pixmap,
  85.               widget->style->black_gc,
  86.               TRUE,
  87.               update_rect.x, update_rect.y,
  88.               update_rect.width, update_rect.height);
  89.  
  90.   /* Now invalidate the affected region of the drawing area. */
  91.   gdk_window_invalidate_rect (widget->window,
  92.                   &update_rect,
  93.                   FALSE);
  94. }
  95.  
  96. static gboolean
  97. scribble_button_press_event (GtkWidget        *widget,
  98.                  GdkEventButton *event,
  99.                  gpointer         data)
  100. {
  101.   if (pixmap == NULL)
  102.     return FALSE; /* paranoia check, in case we haven't gotten a configure event */
  103.   
  104.   if (event->button == 1)
  105.     draw_brush (widget, event->x, event->y);
  106.  
  107.   /* We've handled the event, stop processing */
  108.   return TRUE;
  109. }
  110.  
  111. static gboolean
  112. scribble_motion_notify_event (GtkWidget         *widget,
  113.                   GdkEventMotion *event,
  114.                   gpointer          data)
  115. {
  116.   int x, y;
  117.   GdkModifierType state;
  118.  
  119.   if (pixmap == NULL)
  120.     return FALSE; /* paranoia check, in case we haven't gotten a configure event */
  121.  
  122.   /* This call is very important; it requests the next motion event.
  123.    * If you don't call gdk_window_get_pointer() you'll only get
  124.    * a single motion event. The reason is that we specified
  125.    * GDK_POINTER_MOTION_HINT_MASK to gtk_widget_set_events().
  126.    * If we hadn't specified that, we could just use event->x, event->y
  127.    * as the pointer location. But we'd also get deluged in events.
  128.    * By requesting the next event as we handle the current one,
  129.    * we avoid getting a huge number of events faster than we
  130.    * can cope.
  131.    */
  132.   
  133.   gdk_window_get_pointer (event->window, &x, &y, &state);
  134.     
  135.   if (state & GDK_BUTTON1_MASK)
  136.     draw_brush (widget, x, y);
  137.  
  138.   /* We've handled it, stop processing */
  139.   return TRUE;
  140. }
  141.  
  142.  
  143. static gboolean
  144. checkerboard_expose (GtkWidget        *da,
  145.              GdkEventExpose *event,
  146.              gpointer         data)
  147. {
  148.   gint i, j, xcount, ycount;
  149.   GdkGC *gc1, *gc2;
  150.   GdkColor color;
  151.   
  152. #define CHECK_SIZE 10
  153. #define SPACING 2
  154.   
  155.   /* At the start of an expose handler, a clip region of event->area
  156.    * is set on the window, and event->area has been cleared to the
  157.    * widget's background color. The docs for
  158.    * gdk_window_begin_paint_region() give more details on how this
  159.    * works.
  160.    */
  161.  
  162.   /* It would be a bit more efficient to keep these
  163.    * GC's around instead of recreating on each expose, but
  164.    * this is the lazy/slow way.
  165.    */
  166.   gc1 = gdk_gc_new (da->window);
  167.   color.red = 30000;
  168.   color.green = 0;
  169.   color.blue = 30000;
  170.   gdk_gc_set_rgb_fg_color (gc1, &color);
  171.  
  172.   gc2 = gdk_gc_new (da->window);
  173.   color.red = 65535;
  174.   color.green = 65535;
  175.   color.blue = 65535;
  176.   gdk_gc_set_rgb_fg_color (gc2, &color);
  177.   
  178.   xcount = 0;
  179.   i = SPACING;
  180.   while (i < da->allocation.width)
  181.     {
  182.       j = SPACING;
  183.       ycount = xcount % 2; /* start with even/odd depending on row */
  184.       while (j < da->allocation.height)
  185.     {
  186.       GdkGC *gc;
  187.       
  188.       if (ycount % 2)
  189.         gc = gc1;
  190.       else
  191.         gc = gc2;
  192.  
  193.       /* If we're outside event->area, this will do nothing.
  194.        * It might be mildly more efficient if we handled
  195.        * the clipping ourselves, but again we're feeling lazy.
  196.        */
  197.       gdk_draw_rectangle (da->window,
  198.                   gc,
  199.                   TRUE,
  200.                   i, j,
  201.                   CHECK_SIZE,
  202.                   CHECK_SIZE);
  203.  
  204.       j += CHECK_SIZE + SPACING;
  205.       ++ycount;
  206.     }
  207.  
  208.       i += CHECK_SIZE + SPACING;
  209.       ++xcount;
  210.     }
  211.   
  212.   g_object_unref (gc1);
  213.   g_object_unref (gc2);
  214.   
  215.   /* return TRUE because we've handled this event, so no
  216.    * further processing is required.
  217.    */
  218.   return TRUE;
  219. }
  220.  
  221. GtkWidget *
  222. do_drawingarea (GtkWidget *do_widget)
  223. {
  224.   GtkWidget *frame;
  225.   GtkWidget *vbox;
  226.   GtkWidget *da;
  227.   GtkWidget *label;
  228.   
  229.   if (!window)
  230.     {
  231.       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  232.       gtk_window_set_screen (GTK_WINDOW (window),
  233.                  gtk_widget_get_screen (do_widget));
  234.       gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
  235.  
  236.       g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
  237.  
  238.       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
  239.  
  240.       vbox = gtk_vbox_new (FALSE, 8);
  241.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
  242.       gtk_container_add (GTK_CONTAINER (window), vbox);
  243.  
  244.       /*
  245.        * Create the checkerboard area
  246.        */
  247.       
  248.       label = gtk_label_new (NULL);
  249.       gtk_label_set_markup (GTK_LABEL (label),
  250.                 "<u>Checkerboard pattern</u>");
  251.       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  252.       
  253.       frame = gtk_frame_new (NULL);
  254.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  255.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  256.       
  257.       da = gtk_drawing_area_new ();
  258.       /* set a minimum size */
  259.       gtk_widget_set_size_request (da, 100, 100);
  260.  
  261.       gtk_container_add (GTK_CONTAINER (frame), da);
  262.  
  263.       g_signal_connect (da, "expose_event",
  264.             G_CALLBACK (checkerboard_expose), NULL);
  265.  
  266.       /*
  267.        * Create the scribble area
  268.        */
  269.       
  270.       label = gtk_label_new (NULL);
  271.       gtk_label_set_markup (GTK_LABEL (label),
  272.                 "<u>Scribble area</u>");
  273.       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  274.       
  275.       frame = gtk_frame_new (NULL);
  276.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  277.       gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  278.       
  279.       da = gtk_drawing_area_new ();
  280.       /* set a minimum size */
  281.       gtk_widget_set_size_request (da, 100, 100);
  282.  
  283.       gtk_container_add (GTK_CONTAINER (frame), da);
  284.  
  285.       /* Signals used to handle backing pixmap */
  286.       
  287.       g_signal_connect (da, "expose_event",
  288.             G_CALLBACK (scribble_expose_event), NULL);
  289.       g_signal_connect (da,"configure_event",
  290.             G_CALLBACK (scribble_configure_event), NULL);
  291.       
  292.       /* Event signals */
  293.       
  294.       g_signal_connect (da, "motion_notify_event",
  295.             G_CALLBACK (scribble_motion_notify_event), NULL);
  296.       g_signal_connect (da, "button_press_event",
  297.             G_CALLBACK (scribble_button_press_event), NULL);
  298.  
  299.  
  300.       /* Ask to receive events the drawing area doesn't normally
  301.        * subscribe to
  302.        */
  303.       gtk_widget_set_events (da, gtk_widget_get_events (da)
  304.                  | GDK_LEAVE_NOTIFY_MASK
  305.                  | GDK_BUTTON_PRESS_MASK
  306.                  | GDK_POINTER_MOTION_MASK
  307.                  | GDK_POINTER_MOTION_HINT_MASK);
  308.  
  309.     }
  310.  
  311.   if (!GTK_WIDGET_VISIBLE (window))
  312.     {
  313.       gtk_widget_show_all (window);
  314.     }
  315.   else
  316.     {
  317.       gtk_widget_destroy (window);
  318.       window = NULL;
  319.     }
  320.  
  321.   return window;
  322. }
  323.